package com.tsing.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tsing.wms.config.RedisManager;
import com.tsing.wms.constant.AuthConsts;
import com.tsing.wms.dto.UserDTO;
import com.tsing.wms.entity.*;
import com.tsing.wms.exception.CommonException;
import com.tsing.wms.exception.ServerException;
import com.tsing.wms.mapper.*;
import com.tsing.wms.service.IOrderService;
import com.tsing.wms.util.GetLoginUserUtil;
import com.tsing.wms.valid.ValidList;
import com.tsing.wms.vo.PageResultVO;
import com.tsing.wms.vo.req.IdReqVO;
import com.tsing.wms.vo.req.IdsReqVO;
import com.tsing.wms.vo.req.OrderReqVO;
import com.tsing.wms.vo.req.SupplierPageReqVO;
import com.tsing.wms.vo.resp.GoodsListRespVO;
import com.tsing.wms.vo.resp.OrderRespVO;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author TheTsing
 * @since 2022-04-13
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderEntity> implements IOrderService {

    @Autowired
    private RedisManager redisManager;

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private RecordDetailMapper recordDetailMapper;

    @Override
    public List<GoodsListRespVO> goodsList(IdReqVO reqVO) {
        List<GoodsEntity> goodsEntities = new LambdaQueryChainWrapper<>(goodsMapper)
                .select(GoodsEntity::getId, GoodsEntity::getName, GoodsEntity::getSpecs)
                .eq(GoodsEntity::getSupplierId, reqVO.getId())
                .list();
        return BeanUtil.copyToList(goodsEntities, GoodsListRespVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrder(OrderReqVO reqVO, HttpServletRequest request) {
        if (GetLoginUserUtil.getLoginUserInfo(request.getHeader(AuthConsts.AUTHENTICATION_HEAD), redisManager).getIdentity() != 1) {
            throw new ServerException(CommonException.Proxy.AUTHORIZATION_EXCEPTION);
        }
        OrderEntity orderEntity = new OrderEntity();
        BeanUtil.copyProperties(reqVO, orderEntity);
        baseMapper.insert(orderEntity.setStatus(1));
        ValidList<OrderReqVO.OrderDetailReqVO> orderDetails = reqVO.getOrderDetails();
        orderDetails.forEach(item ->
                recordDetailMapper.insert(new RecordDetailEntity()
                        .setOutRecordId(orderEntity.getId())
                        .setGoodsId(item.getGoodsId())
                        .setAmount(item.getAmount())));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrder(IdsReqVO reqVO, HttpServletRequest request) {
        if (GetLoginUserUtil.getLoginUserInfo(request.getHeader(AuthConsts.AUTHENTICATION_HEAD), redisManager).getIdentity() != 1) {
            throw new ServerException(CommonException.Proxy.AUTHORIZATION_EXCEPTION);
        }
        baseMapper.deleteBatchIds(reqVO.getIds());
        recordDetailMapper.delete(new QueryWrapper<RecordDetailEntity>().in("out_record_id", reqVO.getIds()));
    }

    @Resource
    private UserMapper userMapper;
    @Resource
    private SupplierMapper supplierMapper;

    @Override
    public OrderRespVO getOrder(IdReqVO reqVO) {
        OrderEntity orderEntity = baseMapper.selectById(reqVO.getId());
        OrderRespVO orderRespVO = new OrderRespVO();
        BeanUtil.copyProperties(orderEntity, orderRespVO);
        orderRespVO.setUserName(new LambdaQueryChainWrapper<>(userMapper)
                .select(UserEntity::getUsername)
                .eq(UserEntity::getId, orderRespVO.getUserId())
                .one()
                .getUsername());
        orderRespVO.setPhone(new LambdaQueryChainWrapper<>(userMapper)
                .select(UserEntity::getPhone)
                .eq(UserEntity::getId, orderRespVO.getUserId())
                .one()
                .getPhone());
        SupplierEntity supplierEntity = new LambdaQueryChainWrapper<>(supplierMapper)
                .select(SupplierEntity::getName, SupplierEntity::getUserId)
                .eq(SupplierEntity::getId, orderRespVO.getSupplierId())
                .one();
        orderRespVO.setSupplierName(supplierEntity.getName());
        orderRespVO.setSupplierPhone(new LambdaQueryChainWrapper<>(userMapper)
                .select(UserEntity::getPhone)
                .eq(UserEntity::getId, supplierEntity.getUserId())
                .one()
                .getPhone());
        orderRespVO.setOrderDetails(baseMapper.selectOrderDetails(orderRespVO.getId()));
        return orderRespVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrder(OrderReqVO reqVO, HttpServletRequest request) {
        int originStatus = new LambdaQueryChainWrapper<>(baseMapper)
                .select(OrderEntity::getStatus)
                .eq(OrderEntity::getId, reqVO.getId())
                .one()
                .getStatus();
        if (GetLoginUserUtil.getLoginUserInfo(request.getHeader(AuthConsts.AUTHENTICATION_HEAD), redisManager).getIdentity() != 1) {
            //供应商
            if (ObjectUtil.isNotNull(reqVO.getStatus())) {
                if (reqVO.getStatus() == 1) {
                    if (originStatus == 1) {
                        return;
                    } else {
                        throw new ServerException(CommonException.Proxy.ORDER_CHANGE_ERROR);
                    }
                } else if (reqVO.getStatus() == 2) {
                    if (originStatus == 1) {
                        new LambdaUpdateChainWrapper<>(baseMapper)
                                .set(OrderEntity::getStatus, 2)
                                .eq(OrderEntity::getId, reqVO.getId())
                                .update();
                    } else if (originStatus == 2) {
                        return;
                    } else {
                        throw new ServerException(CommonException.Proxy.ORDER_CHANGE_ERROR);
                    }
                } else {
                    throw new ServerException(CommonException.Proxy.ORDER_CHANGE_ERROR);
                }
            }
        } else {
            //管理员
            if (originStatus == 1) {
                OrderEntity orderEntity = new OrderEntity();
                BeanUtil.copyProperties(reqVO, orderEntity);
                baseMapper.updateById(orderEntity);
                recordDetailMapper.delete(new QueryWrapper<RecordDetailEntity>().eq("out_record_id", reqVO.getId()));
                reqVO.getOrderDetails().forEach(item ->
                        recordDetailMapper.insert(new RecordDetailEntity()
                                .setOutRecordId(reqVO.getId())
                                .setGoodsId(item.getGoodsId())
                                .setAmount(item.getAmount())));
            } else {
                if (ObjectUtil.isNotNull(reqVO.getStatus())) {
                    new LambdaUpdateChainWrapper<>(baseMapper)
                            .set(OrderEntity::getStatus, reqVO.getStatus())
                            .eq(OrderEntity::getId, reqVO.getId())
                            .update();
                }
            }
        }
    }

    @Override
    public PageResultVO<OrderRespVO> orderPage(SupplierPageReqVO reqVO, HttpServletRequest request) {
        IPage<OrderRespVO> page = new Page<>(reqVO.getPageNum(), reqVO.getPageSize());
        UserDTO userDTO = GetLoginUserUtil.getLoginUserInfo(request.getHeader(AuthConsts.AUTHENTICATION_HEAD), redisManager);
        if (userDTO.getIdentity() != 1) {
            baseMapper.orderPage(page, reqVO, userDTO.getId());
        } else {
            //管理员
            baseMapper.orderPage(page, reqVO, null);
        }
        page.getRecords().forEach(item -> {
            item.setGoodsTypeCount(new LambdaQueryChainWrapper<>(recordDetailMapper)
                    .select(RecordDetailEntity::getId)
                    .eq(RecordDetailEntity::getOutRecordId, item.getId())
                    .count());
            item.setGoodsCount(baseMapper.selectGoodsCount(item.getId()));
        });
        return new PageResultVO<>(page);
    }

    @Override
    public void exportOrder(IdReqVO reqVO, HttpServletRequest request, HttpServletResponse response) {
        String fileName = "发货单_" + LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMMddHHmmssS") + ".xlsx";
        OrderRespVO orderRespVO = getOrder(reqVO);
        ExcelWriter writer = ExcelUtil.getWriter(true);
        setStyle(writer);

        writer.merge(0, 0, 0, 5,
                orderRespVO.getSupplierName() + " - " + "发货单" + DateUtil.format(orderRespVO.getCreateTime(), "yyyyMMddHHmmss"), true);
        writer.writeCellValue(0, 1, "订单编号：");
        setCellStyle(writer, 0, 1);
        writer.merge(1, 1, 1, 5, orderRespVO.getId(), false);

        writer.writeCellValue(0, 2, "供应商：");
        setCellStyle(writer, 0, 2);
        writer.writeCellValue(1, 2, orderRespVO.getSupplierName());
        writer.writeCellValue(2, 2, "联系电话：");
        setCellStyle(writer, 2, 2);
        writer.writeCellValue(3, 2, orderRespVO.getSupplierPhone());
        writer.writeCellValue(4, 2, "");
        writer.writeCellValue(5, 2, "");

        writer.writeCellValue(0, 3, "下单人：");
        setCellStyle(writer, 0, 3);
        writer.writeCellValue(1, 3, orderRespVO.getUserName());
        writer.writeCellValue(2, 3, "联系电话：");
        setCellStyle(writer, 2, 3);
        writer.writeCellValue(3, 3, orderRespVO.getPhone());
        writer.writeCellValue(4, 3, "下单时间：");
        setCellStyle(writer, 4, 3);
        writer.writeCellValue(5, 3, DateUtil.formatDateTime(orderRespVO.getCreateTime()));
        int i = 4;
        writer.merge(i, i, 0, 1, "货物名称", false);
        setCellStyle(writer, 0, i);
        writer.merge(i, i, 2, 3, "规格", false);
        setCellStyle(writer, 2, i);
        writer.writeCellValue(4, i, "价格（元）");
        setCellStyle(writer, 4, i);
        writer.writeCellValue(5, i, "数量");
        setCellStyle(writer, 5, i);

        for (OrderRespVO.OrderDetailRespVO orderDetail : orderRespVO.getOrderDetails()) {
            i++;
            writer.merge(i, i, 0, 1, orderDetail.getGoodsName(), false);
            writer.merge(i, i, 2, 3, orderDetail.getSpecs(), false);
            writer.writeCellValue(4, i, orderDetail.getPrice());
            writer.writeCellValue(5, i, orderDetail.getAmount());
        }

        writer.writeCellValue(0, ++i, "备注：");
        setCellStyle(writer, 0, i);
        writer.merge(i, i, 1, 5, orderRespVO.getDescription(), false);

        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
        }
        writer.close();
    }

    private void setStyle(ExcelWriter writer) {
        StyleSet styleSet = writer.getStyleSet();
        // 设置标题样式
        CellStyle headCellStyle = styleSet.getHeadCellStyle();
        Font font = writer.createFont();
        font.setFontName("宋体");
        font.setBold(true);
        font.setFontHeightInPoints((short) 14);
        headCellStyle.setFont(font);
        // 背景颜色
        styleSet.setBackgroundColor(IndexedColors.WHITE, true);
        writer.setStyleSet(styleSet);
        writer.setColumnWidth(-1, 25);
        writer.setRowHeight(0, 30);
        writer.setDefaultRowHeight(25);
    }

    private void setCellStyle(ExcelWriter writer, int x, int y) {
        CellStyle cellStyle = writer.createCellStyle(x, y);
        Font font = writer.createFont();
        font.setBold(true);
        cellStyle.setFont(font);
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
    }

}
